package parallel.project.graph;

import java.awt.Point;
import java.io.IOException;

import parallel.project.framework.MazeException;
import parallel.project.framework.Mazemap;
import parallel.project.framework.Serializer;
import parallel.project.solver.MazeToGraphMaster;

/**
 * A factory for creating {@link Graph}s in different ways
 * 
 * Copyright 2011
 * @author Adam Clayton
 * @author Larry Walters
 */
public class GraphFactory 
{
	/** Last maze used for making a {@link Graph} */
	Mazemap lastMaze;
	
	public GraphFactory() {}
	
	/**
	 * Reads in a maze file created with {@link MazeGenerator}, and 
	 * thus defined by {@link Mazemap}, and converts it to a
	 * {@link Graph} where every {@link Node} is a branch in a passage
	 * (i.e. where there are multiple directions to go in), and each
	 * {@link Edge} represents the passages between these branch 
	 * locations, and the length of them is their weight.  The locations
	 * of the {@link Node}s and {@link Edge}s come from the 2D 
	 * coordinates of the maze.  Note that this {@link Graph} is
	 * pruned so that dead ends are removed and intermediate nodes that
	 * have just two edges coming from them are removed.
	 * 
	 * @param filename
	 * 		Name of the file to read the {@link Mazemap} from
	 * @param threads
	 * 		The number of threads used in converting the maze to a
	 * 		{@link Graph}
	 * 
	 * @return
	 * 		{@link Graph} representation of this maze
	 * @throws ClassNotFoundException
	 * @throws IOException
	 */
	public Graph makeMazemapGraph(String filename, int threads)
		throws ClassNotFoundException,IOException,MazeException
	{
		// read from file into a new Mazemap object
		Mazemap maze = Serializer.readObject(new Mazemap(),filename);
		this.lastMaze = maze;
//		if (maze != null)
//		{
//			System.out.println(filename + " read successfully");
//			maze.printMazemap();
//		}
		// convert the maze to a graph and return it
		return this.makeMazemapGraph(maze,threads);
	}
	
	/**
	 * Converts a maze defined in the <code>maze</code> object it to a
	 * {@link Graph} where every {@link Node} is a branch in a passage
	 * (i.e. where there are multiple directions to go in), and each
	 * {@link Edge} represents the passages between these branch 
	 * locations, and the length of them is their weight.  The locations
	 * of the {@link Node}s and {@link Edge}s come from the 2D 
	 * coordinates of the maze.  Note that this {@link Graph} is
	 * pruned so that dead ends are removed and intermediate nodes that
	 * have just two edges coming from them are removed.
	 * 
	 * @param maze
	 * 		Maze to convert
	 * @param threads
	 * 		The number of threads used in converting the maze to a
	 * 		{@link Graph}
	 * 
	 * @return
	 * 		{@link Graph} representation of this maze
	 */	
	public Graph makeMazemapGraph(Mazemap maze, int threads)
		throws MazeException
	{
//		Graph graph = null;
		this.lastMaze = maze;
//		System.out.println("Make master");
		// create the master, which will just "run" in this main thread
		MazeToGraphMaster master = new MazeToGraphMaster();
		// give the maze to the master, and tell it to use the given
		// number of slave solvers (threads) to partition and make the
		// the graph
		System.out.println("Starting algorithm");
		master.startSolvers(threads,maze);
		// wait till the algorithm is done
		master.waitTillDone();
		System.out.println("Algorithm done");
//		try
//		{
//			synchronized(Thread.currentThread())
//			{
//				while (!master.isEnded())
//					Thread.currentThread().wait(1000);
//				Thread.currentThread().notify()
//				graph = master.getGraph();
//			}
//		} catch (InterruptedException ie) {return null;}
		
		Graph graph = master.getGraph();
//		try {graph.toDot("final.dot");}
//		catch (Exception e) {}
		
		return graph;
		
//		// beginning from the start location, do the following: at 
//		// every spot, see if there are any other open passages 
//		// immediately (the 8 spots) around it, if there are, and there
//		// are more than 1, this is a node (the start and end are nodes
//		// automatically). If there is only one, then that is the next
//		// location in the edge from the current node to the next one 
//		// will come to in the future (either the next branch, or the 
//		// end node). A deadend is a node as well. In this way, compile
//		// nodes and the edges between them, and the locations of each
//		// to make a full graph
//		
//		return null;
	}

	/**
	 * Returns the last maze that was used for making a {@link Graph},
	 * whether the {@link Graph} was successfully made or not.
	 * 
	 * @return
	 * 		Last maze dealt with
	 */
	public Mazemap getLastMaze() 
	{
		return this.lastMaze;
	}
}
